package com.atguigu.gmall.cart.service;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 李旭
 * @date 2021/10/18 15:27
 * @Description:
 */
@SuppressWarnings("all")
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper,CartInfo> implements CartInfoService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private CartInfoSyncService cartInfoSyncService;


    //加入购物车 == 加
    @Override
    public void addToCart(Long skuId, Integer skuNum, String userId) {
        System.out.println("主线程的名称：" + Thread.currentThread().getName());
        //（重要）1:保存购物车到Redis缓存中
        //Hash   Map h   h.put(hk(手机ID),手机)  h:userId
        //Hash   Map h   h.put(hk(电脑ID),电脑)
        //Hash   Map h   h.put(hk,冰箱)
        // h  user:3:cart   真实用户的购物车
        // h  user:abgsrdffgrfsdgrfg:cart  临时用户的购物车
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //1.1 查询缓存中的购物车
        //List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        if (null != cartInfo) {
            //此用户在之前已经加入过此商品  本次追加数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //（不重要） 2:保存购物车到DB中   2写
            cartInfoSyncService.updateCartInfo(cartInfo);//800ms   异步
        } else {
            //此用户在之前没有添加过此商品  添加此商品
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);//缓存
            BigDecimal price = productFeignClient.getPrice(skuId);
            cartInfo.setCartPrice(price);//实时价格
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            //（不重要） 2:保存购物车到DB中   2写
            cartInfoSyncService.insertCartInfo(cartInfo);//800ms   异步
        }
        //走了加入购物车之后 必须勾选上
        cartInfo.setIsChecked(1);
        //保存回缓存   1写
        redisTemplate.opsForHash().put(cartHKey, skuId.toString(), cartInfo);//200ms
    }

    //加入购物车 == 查
    @Override
    public CartInfo toCart(Long skuId) {
        //任意位置 获取Request对象
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if(StringUtils.isEmpty(userId)){
            //临时用户ID  万一之前加入购物车  有了真实用户ID之后 之前临时用户ID加的那些商品还在吗
            userId = AuthContextHolder.getUserTempId(request);
        }
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        return (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
    }

    //查询购物车集合   逻辑开发  百度查一波
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //当前用户：
        // 如果登录了应该查询（真实用户的 + 临时用户的）  临时用户的购物车清空
        // 如果未登录是临时用户的购物车集合
        //1:判断用户是否登录
        if(!StringUtils.isEmpty(userId)){
            //登录了  有真实用户的ID
            if(!StringUtils.isEmpty(userTempId)){
                //有真实用户的ID 临时用户ID也是有
                //大合并
                return mergeCartInfoList(userId,userTempId);
            }else{
                //有真实用户的ID 但是没有临时用户的ID
                return getCartInfoList(userId);
            }
        }else{
            //未登录  没有真实用户的ID
            if(!StringUtils.isEmpty(userTempId)){
                //临时用户ID是有的
                return getCartInfoList(userTempId);
            }else{
                //临时用户ID都没有 哪来的购物车集合
                return null;
            }

        }
    }

    //选中或取消
    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if(StringUtils.isEmpty(userId)){
            //临时用户ID  万一之前加入购物车  有了真实用户ID之后 之前临时用户ID加的那些商品还在吗
            userId = AuthContextHolder.getUserTempId(request);
        }
        //1:缓存
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cartHKey,skuId.toString(),cartInfo);
        //2:DB    后台管理员
        cartInfoSyncService.updateCartInfo(cartInfo);

    }
    //查询商品清单   结论： 购物车中已经选中的商品集合  B/S 电脑 浏览器     C/S   Client客户端
    @Override
    public List<CartInfo> getCartInfoListByChecked(String userId) {
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        // 过滤： 已经选中的要  取消的不要
        return cartInfoList.stream().filter(cartInfo -> 1 == cartInfo.getIsChecked()).
                peek(cartInfo -> {
                    //查询实时价格
                    BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
                    cartInfo.setSkuPrice(price);
                })
                .collect(Collectors.toList());
        //peek  约等 foreach  区别：foreach结束   peek后面还可以继续filter sorted
    }

    //大合并
    private List<CartInfo> mergeCartInfoList(String userId, String userTempId) {
        //1:获取购物车集合（真实用户ID ）
        List<CartInfo> cartInfoListByUserId = getCartInfoList(userId);
        //2:获取购物车集合（临时用户ID ）
        List<CartInfo> cartInfoListByUserTempId = getCartInfoList(userTempId);
        //3:开始合并
        if(!CollectionUtils.isEmpty(cartInfoListByUserId)){
            //真实用户的购物车集合 是有的
            if(!CollectionUtils.isEmpty(cartInfoListByUserTempId)){
                //才开始真正的大合并
                //Map K : skuId   V: CartInfo
                Map<String, CartInfo> mapByUserId = cartInfoListByUserId.stream().collect(Collectors.toMap(
                        cartInfo -> cartInfo.getSkuId().toString(),
                        cartInfo -> cartInfo));
                //3.1： 遍历临时购物车集合
                for (CartInfo cartInfoByUserTempId : cartInfoListByUserTempId) {
                    //skuId
                    CartInfo cartInfoByUserId = mapByUserId.get(cartInfoByUserTempId.getSkuId().toString());
                    if(null != cartInfoByUserId){
                        //3.2:  遇到相同商品追加数量
                        cartInfoByUserId.setSkuNum(cartInfoByUserId.getSkuNum() +
                                cartInfoByUserTempId.getSkuNum());
                        cartInfoByUserId.setIsChecked(1);
                    }else{
                        //3.3:  遇到不相同的商品添加新商品
                        cartInfoByUserTempId.setUserId(userId);
                        mapByUserId.put(cartInfoByUserTempId.getSkuId().toString(),cartInfoByUserTempId);
                    }
                }
                //统一 处理 删除 此（真实用户ID + 临时用户的ID）
                cartInfoMapper.delete(new QueryWrapper<CartInfo>()
                 .in("user_id",userId,userTempId));

                List<CartInfo> cartInfoList = new ArrayList<>(mapByUserId.values());
                //统一将最新购物车集合 添加 （批量）
                this.saveBatch(cartInfoList);// insert into cart_info values (),(),(),(),(),(),(),()
                //统一删除Redis中临时用户的hash
                String cartHKeyByUserTempId = RedisConst.USER_KEY_PREFIX + userTempId
                        + RedisConst.USER_CART_KEY_SUFFIX;
                redisTemplate.delete(cartHKeyByUserTempId);
                //统一更新
                String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
                redisTemplate.opsForHash().putAll(cartHKey,mapByUserId);
                //return (List<CartInfo>) mapByUserId.values();//误解   执行的时候 抛出异常 强转异常
                return cartInfoList;//正解
            }else{
                //临时用户的购物车集合是没有
                return cartInfoListByUserId;
            }
        }else{
            //真实用户的购物车集合 没有 直接返回临时用户的购物车集合
            return cartInfoListByUserTempId;
        }
    }

    //获取购物车集合 根据用户的ID
    private List<CartInfo> getCartInfoList(String userId) {
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        //排序  价格  ID  时间
        return cartInfoList.stream().peek(cartInfo -> {
            //查询实时价格
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        }).sorted((cartInfo1, cartInfo2) -> {
            return cartInfo2.getSkuPrice().intValue() - cartInfo1.getSkuPrice().intValue();
        }).collect(Collectors.toList());

    }
}
